// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf

#include "MgcOglRenderer.h"
#include "MgcParticles.h"
#include "MgcPolyline.h"
#include "MgcPolypoint.h"
#include "MgcTriMesh.h"

MgcImplementRTTI(MgcOglRenderer,MgcRenderer);

//----------------------------------------------------------------------------
MgcOglRenderer::MgcOglRenderer (HWND hWnd, int iWidth, int iHeight)
    :
    MgcRenderer(iWidth,iHeight)
{
    CreateRenderer(hWnd);
}
//----------------------------------------------------------------------------
MgcOglRenderer::MgcOglRenderer ()
{
}
//----------------------------------------------------------------------------
MgcOglRenderer::~MgcOglRenderer ()
{
    if ( m_hWindowRC )
        wglDeleteContext(m_hWindowRC);

    if ( m_hWindowDC )
        ReleaseDC(m_hWnd,m_hWindowDC);
}
//----------------------------------------------------------------------------
void MgcOglRenderer::CreateRenderer (HWND hWnd)
{
    assert( m_iWidth > 0 && m_iHeight > 0 );

    m_hWnd = hWnd;
    m_hWindowDC = GetDC(m_hWnd);

    // select format for drawing surface
    PIXELFORMATDESCRIPTOR kPFD;
    memset(&kPFD,0,sizeof(PIXELFORMATDESCRIPTOR));
    kPFD.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    kPFD.nVersion = 1;
    kPFD.dwFlags =
        PFD_DRAW_TO_WINDOW |
        PFD_SUPPORT_OPENGL |
        PFD_GENERIC_ACCELERATED |
        PFD_DOUBLEBUFFER;
    kPFD.iPixelType = PFD_TYPE_RGBA;
    kPFD.cColorBits = 16;  // 16-bit colors for front/back buffers
    kPFD.cDepthBits = 16;  // 16-bit depth buffer
    
    // set the pixel format for the rendering context
    int iPixelFormat = ChoosePixelFormat(m_hWindowDC,&kPFD);
    if ( iPixelFormat == 0 )
        return;

    BOOL bSuccess = SetPixelFormat(m_hWindowDC,iPixelFormat,&kPFD);
    if ( !bSuccess )
        return;

    // create an OpenGL context
    m_hWindowRC = wglCreateContext(m_hWindowDC);
    if ( !m_hWindowRC )
        return;

    bSuccess = wglMakeCurrent(m_hWindowDC,m_hWindowRC);
    if ( !bSuccess )
        return;

    GetDriverInformation();
    InitializeState();
}
//----------------------------------------------------------------------------
void MgcOglRenderer::GetDriverInformation ()
{
    // get OpenGL extensions
    char* acVendor = (char*) glGetString(GL_VENDOR);
    char* acRenderer = (char*) glGetString(GL_RENDERER);
    char* acVersion = (char*) glGetString(GL_VERSION);
    char* acGluVersion = (char*) gluGetString(GLU_VERSION);

    char* acExtensions =
        new char[strlen((const char*)glGetString(GL_EXTENSIONS))+1];
    strcpy_s(acExtensions,strlen((const char*)glGetString(GL_EXTENSIONS))+1,(const char*)glGetString(GL_EXTENSIONS));

    // create message buffer (include space for prefixs and null terminator)
    int iMaxLength = strlen(acVendor);
    int iLength = strlen(acRenderer);
    if ( iLength > iMaxLength )
        iMaxLength = iLength;
    iLength = strlen(acVersion);
    if ( iLength > iMaxLength )
        iMaxLength = iLength;
    iLength = strlen(acGluVersion);
    if ( iLength > iMaxLength )
        iMaxLength = iLength;
    iLength = strlen(acExtensions);
    if ( iLength > iMaxLength )
        iMaxLength = iLength;
    iMaxLength += 16;

    char* acMessage = new char[iMaxLength];

    sprintf_s(acMessage,iMaxLength,"Vendor: %s\n",acVendor);
    OutputDebugString(acMessage);

    sprintf_s(acMessage,iMaxLength,"Renderer: %s\n",acRenderer);
    OutputDebugString(acMessage);

    sprintf_s(acMessage,iMaxLength,"Version: %s\n",acVersion);
    OutputDebugString(acMessage);

    sprintf_s(acMessage,iMaxLength,"GLU Version: %s\n",acGluVersion);
    OutputDebugString(acMessage);

    OutputDebugString("Extensions:\n");

	char* nextToken = 0;
    char* acToken = strtok_s(acExtensions," \t\r\n", &nextToken);
    while ( acToken )
    {
        sprintf_s(acMessage,iMaxLength,"  %s\n",acToken);
        OutputDebugString(acMessage);
        acToken = strtok_s(0," \t\r\n", &nextToken);
    }

    delete[] acExtensions;
    delete[] acMessage;
}
//----------------------------------------------------------------------------
void MgcOglRenderer::SetBackgroundColor (const MgcColor& rkColor)
{
    MgcRenderer::SetBackgroundColor(rkColor);
    glClearColor(rkColor.r,rkColor.g,rkColor.b,1.0f);
}
//---------------------------------------------------------------------------
void MgcOglRenderer::ClearBackBuffer ()
{
    glDisable(GL_DITHER);
    glEnable(GL_SCISSOR_TEST);
    glScissor(0,0,m_iWidth,m_iHeight);
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_SCISSOR_TEST);
    glEnable(GL_DITHER);
}
//----------------------------------------------------------------------------
void MgcOglRenderer::DisplayBackBuffer ()
{
    glFlush();
    SwapBuffers(m_hWindowDC);
}
//----------------------------------------------------------------------------
void MgcOglRenderer::ClearZBuffer ()
{
    glDisable(GL_DITHER);
    glEnable(GL_SCISSOR_TEST);
    glScissor(0,0,m_iWidth,m_iHeight);
    glClear(GL_DEPTH_BUFFER_BIT);
    glDisable(GL_SCISSOR_TEST);
    glEnable(GL_DITHER);
}
//----------------------------------------------------------------------------
void MgcOglRenderer::ClearBuffers ()
{
    glDisable(GL_DITHER);
    glEnable(GL_SCISSOR_TEST);
    glScissor(0,0,m_iWidth,m_iHeight);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_SCISSOR_TEST);
    glEnable(GL_DITHER);
}
//----------------------------------------------------------------------------
void MgcOglRenderer::InitializeState ()
{
    MgcRenderer::InitializeState();

    // do back face culling (front faces are counterclockwise ordered)
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    glFrontFace(GL_CCW);

    // vertices always exist
    glEnableClientState(GL_VERTEX_ARRAY);

    // no global ambient lighting
    GLfloat afBlack[4] = { 0.0, 0.0, 0.0, 1.0 };
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT,afBlack);
}
//----------------------------------------------------------------------------
void MgcOglRenderer::Draw (const MgcTriMesh& rkMesh)
{
    // set world matrix
    const MgcMatrix3& rkRot = rkMesh.WorldRotate();
    const MgcVector3& rkTrn = rkMesh.WorldTranslate();
    MgcReal fScale = rkMesh.WorldScale();
    GLfloat afModelToWorld[16] =
    {
        fScale*rkRot[0][0], fScale*rkRot[1][0], fScale*rkRot[2][0], 0.0f,
        fScale*rkRot[0][1], fScale*rkRot[1][1], fScale*rkRot[2][1], 0.0f,
        fScale*rkRot[0][2], fScale*rkRot[1][2], fScale*rkRot[2][2], 0.0f,
        rkTrn.x,            rkTrn.y,            rkTrn.z,            1.0f
    };

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glMultMatrixf(afModelToWorld);

    // render the object
    GLfloat* afVertices = (GLfloat*) rkMesh.Vertices();
    glVertexPointer(3,GL_FLOAT,0,afVertices);

    GLfloat* afNormals = (GLfloat*) rkMesh.Normals();
    if ( afNormals )
    {
        glEnableClientState(GL_NORMAL_ARRAY);
        glNormalPointer(GL_FLOAT,0,afNormals);
    }
    else
    {
        glDisableClientState(GL_NORMAL_ARRAY);
    }

    GLfloat* afColors = (GLfloat*) rkMesh.Colors();
    if ( afColors )
    {
        glEnableClientState(GL_COLOR_ARRAY);
        glColorPointer(3,GL_FLOAT,0,afColors);
    }
    else
    {
        glDisableClientState(GL_COLOR_ARRAY);
    }

    GLfloat* afTextures = (GLfloat*) rkMesh.Textures();
    if ( afTextures )
    {
        glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
        glTexCoordPointer(2,GL_FLOAT,0,afTextures);
    }
    else
    {
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

    glDrawElements(GL_TRIANGLES,3*rkMesh.GetTriangleQuantity(),
        GL_UNSIGNED_INT,rkMesh.Connectivity());

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}
//----------------------------------------------------------------------------
void MgcOglRenderer::Draw (const MgcPolyline& rkLine)
{
    // set world matrix
    const MgcMatrix3& rkRot = rkLine.WorldRotate();
    const MgcVector3& rkTrn = rkLine.WorldTranslate();
    MgcReal fScale = rkLine.WorldScale();
    GLfloat afModelToWorld[16] =
    {
        fScale*rkRot[0][0], fScale*rkRot[1][0], fScale*rkRot[2][0], 0.0f,
        fScale*rkRot[0][1], fScale*rkRot[1][1], fScale*rkRot[2][1], 0.0f,
        fScale*rkRot[0][2], fScale*rkRot[1][2], fScale*rkRot[2][2], 0.0f,
        rkTrn.x,            rkTrn.y,            rkTrn.z,            1.0f
    };

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glMultMatrixf(afModelToWorld);

    // render the object
    glBegin(GL_LINES);

    // draw line
    const MgcVector3* akVertex = rkLine.Vertices();
    const MgcVector3* akNormal = rkLine.Normals();
    const MgcColor* akColor = rkLine.Colors();
    const MgcVector2* akTexture = rkLine.Textures();

    unsigned int uiL, uiLMax = rkLine.GetVertexQuantity() - 1;

    if ( akNormal )
    {
        if ( akColor )
        {
            if ( akTexture )
            {
                // N,C,T
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glNormal3fv((GLfloat*)akNormal);
                    glColor3fv((GLfloat*)akColor);
                    glTexCoord2fv((GLfloat*)akTexture);
                    glVertex3fv((GLfloat*)akVertex);
                    glNormal3fv((GLfloat*)rkLine.Normals());
                    glColor3fv((GLfloat*)rkLine.Colors());
                    glTexCoord2fv((GLfloat*)rkLine.Textures());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
            else
            {
                // N,C
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glNormal3fv((GLfloat*)akNormal);
                    glColor3fv((GLfloat*)akColor);
                    glVertex3fv((GLfloat*)akVertex);
                    glNormal3fv((GLfloat*)rkLine.Normals());
                    glColor3fv((GLfloat*)rkLine.Colors());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
        }
        else
        {
            if ( akTexture )
            {
                // N,T
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glNormal3fv((GLfloat*)akNormal++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glNormal3fv((GLfloat*)akNormal);
                    glTexCoord2fv((GLfloat*)akTexture);
                    glVertex3fv((GLfloat*)akVertex);
                    glNormal3fv((GLfloat*)rkLine.Normals());
                    glTexCoord2fv((GLfloat*)rkLine.Textures());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
            else
            {
                // N
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glNormal3fv((GLfloat*)akNormal++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glNormal3fv((GLfloat*)akNormal);
                    glVertex3fv((GLfloat*)akVertex);
                    glNormal3fv((GLfloat*)rkLine.Normals());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
        }
    }
    else
    {
        if ( akColor )
        {
            if ( akTexture )
            {
                // C,T
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glColor3fv((GLfloat*)akColor++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glColor3fv((GLfloat*)akColor++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glColor3fv((GLfloat*)akColor);
                    glTexCoord2fv((GLfloat*)akTexture);
                    glVertex3fv((GLfloat*)akVertex);
                    glColor3fv((GLfloat*)rkLine.Colors());
                    glTexCoord2fv((GLfloat*)rkLine.Textures());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
            else
            {
                // C
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glColor3fv((GLfloat*)akColor++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glColor3fv((GLfloat*)akColor++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glColor3fv((GLfloat*)akColor);
                    glVertex3fv((GLfloat*)akVertex);
                    glColor3fv((GLfloat*)rkLine.Colors());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
        }
        else
        {
            if ( akTexture )
            {
                // T
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }

                if ( rkLine.Closed() )
                {
                    glTexCoord2fv((GLfloat*)akTexture);
                    glVertex3fv((GLfloat*)akVertex);
                    glTexCoord2fv((GLfloat*)rkLine.Textures());
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
            else
            {
                // none
                for (uiL = 0; uiL < uiLMax; uiL++)
                {
                    glVertex3fv((GLfloat*)akVertex++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
        
                if ( rkLine.Closed() )
                {
                    glVertex3fv((GLfloat*)akVertex);
                    glVertex3fv((GLfloat*)rkLine.Vertices());
                }
            }
        }
    }

    glEnd();

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}
//----------------------------------------------------------------------------
void MgcOglRenderer::Draw (const MgcPolypoint& rkPoint)
{
    // set world matrix
    const MgcMatrix3& rkRot = rkPoint.WorldRotate();
    const MgcVector3& rkTrn = rkPoint.WorldTranslate();
    MgcReal fScale = rkPoint.WorldScale();
    GLfloat afModelToWorld[16] =
    {
        fScale*rkRot[0][0], fScale*rkRot[1][0], fScale*rkRot[2][0], 0.0f,
        fScale*rkRot[0][1], fScale*rkRot[1][1], fScale*rkRot[2][1], 0.0f,
        fScale*rkRot[0][2], fScale*rkRot[1][2], fScale*rkRot[2][2], 0.0f,
        rkTrn.x,            rkTrn.y,            rkTrn.z,            1.0f
    };

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glMultMatrixf(afModelToWorld);

    // render the object
    glBegin(GL_POINTS);

    // draw points
    const MgcVector3* akVertex = rkPoint.Vertices();
    const MgcVector3* akNormal = rkPoint.Normals();
    const MgcColor* akColor = rkPoint.Colors();
    const MgcVector2* akTexture = rkPoint.Textures();

    unsigned int uiP, uiPMax = rkPoint.GetVertexQuantity();

    if ( akNormal )
    {
        if ( akColor )
        {
            if ( akTexture )
            {
                // N,C,T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
            else
            {
                // N,C
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
        }
        else
        {
            if ( akTexture )
            {
                // N,T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
            else
            {
                // N
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glNormal3fv((GLfloat*)akNormal++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
        }
    }
    else
    {
        if ( akColor )
        {
            if ( akTexture )
            {
                // C,T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glColor3fv((GLfloat*)akColor++);
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
            else
            {
                // C
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glColor3fv((GLfloat*)akColor++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
        }
        else
        {
            if ( akTexture )
            {
                // T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glTexCoord2fv((GLfloat*)akTexture++);
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
            else
            {
                // none
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    glVertex3fv((GLfloat*)akVertex++);
                }
            }
        }
    }

    glEnd();

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}
//----------------------------------------------------------------------------
void MgcOglRenderer::Draw (const MgcParticles& rkParticle)
{
    // set world matrix
    const MgcMatrix3& rkRot = rkParticle.WorldRotate();
    const MgcVector3& rkTrn = rkParticle.WorldTranslate();
    MgcReal fScale = rkParticle.WorldScale();
    GLfloat afModelToWorld[16] =
    {
        fScale*rkRot[0][0], fScale*rkRot[1][0], fScale*rkRot[2][0], 0.0f,
        fScale*rkRot[0][1], fScale*rkRot[1][1], fScale*rkRot[2][1], 0.0f,
        fScale*rkRot[0][2], fScale*rkRot[1][2], fScale*rkRot[2][2], 0.0f,
        rkTrn.x,            rkTrn.y,            rkTrn.z,            1.0f
    };

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glMultMatrixf(afModelToWorld);

    // render the object
    glBegin(GL_QUADS);

    // draw particles
    const MgcVector3* akVertex = rkParticle.Vertices();
    const MgcVector3* akNormal = rkParticle.Normals();
    const MgcColor* akColor = rkParticle.Colors();
    const MgcReal* afSize = rkParticle.Sizes();
    MgcReal fSizeAdjust = rkParticle.SizeAdjust();
    MgcVector3 kUpL = m_spkCamera->GetUp() + m_spkCamera->GetLeft();
    MgcVector3 kUmL = m_spkCamera->GetUp() - m_spkCamera->GetLeft();

    unsigned int uiP, uiPMax = rkParticle.GetActiveQuantity();
    MgcVector3 kScaledUpL, kScaledUmL;
    MgcVector3 kOrigin, kCpp, kCpm, kCmp, kCmm;
    MgcReal fTrueSize;

    if ( akNormal )
    {
        if ( akColor )
        {
            if ( rkParticle.UseTexture() )
            {
                // N,C,T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glTexCoord2f(0.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmm);
                    glTexCoord2f(0.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpm);
                    glTexCoord2f(1.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpp);
                    glTexCoord2f(1.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
            else
            {
                // N,C
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;
                    glNormal3fv((GLfloat*)akNormal++);
                    glColor3fv((GLfloat*)akColor++);

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glVertex3fv((GLfloat*)&kCmm);
                    glVertex3fv((GLfloat*)&kCpm);
                    glVertex3fv((GLfloat*)&kCpp);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
        }
        else
        {
            if ( rkParticle.UseTexture() )
            {
                // N,T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;
                    glNormal3fv((GLfloat*)akNormal++);

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glTexCoord2f(0.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmm);
                    glTexCoord2f(0.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpm);
                    glTexCoord2f(1.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpp);
                    glTexCoord2f(1.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
            else
            {
                // N
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;
                    glNormal3fv((GLfloat*)akNormal++);

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glVertex3fv((GLfloat*)&kCmm);
                    glVertex3fv((GLfloat*)&kCpm);
                    glVertex3fv((GLfloat*)&kCpp);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
        }
    }
    else
    {
        if ( akColor )
        {
            if ( rkParticle.UseTexture() )
            {
                // C,T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;
                    glColor3fv((GLfloat*)akColor++);

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glTexCoord2f(0.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmm);
                    glTexCoord2f(0.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpm);
                    glTexCoord2f(1.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpp);
                    glTexCoord2f(1.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
            else
            {
                // C
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;
                    glColor3fv((GLfloat*)akColor++);

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glVertex3fv((GLfloat*)&kCmm);
                    glVertex3fv((GLfloat*)&kCpm);
                    glVertex3fv((GLfloat*)&kCpp);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
        }
        else
        {
            if ( rkParticle.UseTexture() )
            {
                // T
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glTexCoord2f(0.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmm);
                    glTexCoord2f(0.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpm);
                    glTexCoord2f(1.0f,1.0f);
                    glVertex3fv((GLfloat*)&kCpp);
                    glTexCoord2f(1.0f,0.0f);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
            else
            {
                // none
                for (uiP = 0; uiP < uiPMax; uiP++)
                {
                    kOrigin = *akVertex++;

                    fTrueSize = fSizeAdjust*(*afSize++);
                    kScaledUpL = fTrueSize*kUpL;
                    kScaledUmL = fTrueSize*kUmL;
                    kCpp = kOrigin + kScaledUpL;
                    kCpm = kOrigin + kScaledUmL;
                    kCmp = kOrigin - kScaledUmL;
                    kCmm = kOrigin - kScaledUpL;

                    glVertex3fv((GLfloat*)&kCmm);
                    glVertex3fv((GLfloat*)&kCpm);
                    glVertex3fv((GLfloat*)&kCpp);
                    glVertex3fv((GLfloat*)&kCmp);
                }
            }
        }
    }


    glEnd();

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}
//----------------------------------------------------------------------------
void MgcOglRenderer::Draw (int iX, int iY, const char* acText)
{
    assert( acText );

    BYTE bR = (BYTE)(255.0*m_kBackgroundColor.r);
    BYTE bG = (BYTE)(255.0*m_kBackgroundColor.g);
    BYTE bB = (BYTE)(255.0*m_kBackgroundColor.b);
    SetTextColor(m_hWindowDC,RGB(255,255,255));
    SetBkColor(m_hWindowDC,RGB(bR,bG,bB));
    SetTextAlign(m_hWindowDC,TA_BOTTOM);
    TextOut(m_hWindowDC,iX,iY,acText,strlen(acText));
}
//----------------------------------------------------------------------------

//---------------------------------------------------------------------------
// debugging
//---------------------------------------------------------------------------
bool MgcOglRenderer::OperationOkay ()
{
    GLenum eCode = glGetError();
    if ( eCode == GL_NO_ERROR )
        return true;

    char acMsg[128];
    sprintf_s(acMsg,128,"Error: %s\n",gluErrorString(eCode));
    OutputDebugString(acMsg);
    return false;
}
//---------------------------------------------------------------------------
